package view;

import h2d.Bitmap;
import hxd.Math;
import hxmath.math.MathUtil;
import hxmath.math.IntVector2;
import hxmath.geom.Rect;
import hxmath.math.Vector2;
import h3d.Vector;
import hxd.Key;
import cmd.Cmd_DrawPixel;
import cmd.Root_Cmd;
import hxd.Rand;
import hxd.Event.EventKind;
import tree.LeafMsg;
import tree.LeafKind;
import view.UICompents.GridComp;
import view.UICompents.LineComp;
import tree.Root;
import data.Data_Canvas;
import hxd.fmt.grd.Data.Color;
import h2d.Tile;
import h2d.domkit.BaseComponents.FlowComp;
import hxd.res.TiledMap;
import h2d.domkit.Style;
import h2d.domkit.Object;
import h2d.Flow;

@:uiComp("view-canvas")
class ViewCanvasComp extends Flow implements Object {
    static var SRC = 
    <view-canvas>
        <bitmap public id = "bitmap_canvas"/>
    </view-canvas>
    
    public function new(?parent) {
		super(parent);
		initComponent();
	}
}


//画板结伴
class View_Canvas extends ViewTress<ViewCanvasComp> {
    static var max_event_count = 1;
    var isLeftButton : Bool;
    var isRightButton : Bool;
    var isCtrlDown : Bool;
    //给子的事件数量
    var remainEventCount : Int;
    var lastPos : Vector2;
    
    
    public function new(?view : ViewCanvasComp) {
        super(ViewCanvasComp, view);
        lastPos = new Vector2(0, 0);
    }
    
    public override function OnEnter(last:LeafKind) {
        super.OnEnter(last);
    
	}

    public override function OnUpdate(msg:LeafMsg)
    {
        super.OnUpdate(msg);
        remainEventCount = 1;
        if(msg == null){
            return;
        }
        switch (msg){
            case WindowEvent(e):
                if(e.kind == EventKind.EPush && e.button == 0){
                    isLeftButton = true;
                    TriggerEvent(lastPos, new Vector2(e.relX, e.relY));
                }
                else if(e.kind == EventKind.ERelease && e.button == 0){
                    isLeftButton = false;
                }
                else if(e.kind == EventKind.EPush && e.button == 1){
                    isRightButton = true;
                    TriggerEvent(lastPos, new Vector2(e.relX, e.relY));
                }
                else if(e.kind == EventKind.ERelease && e.button == 1){
                    isRightButton = false;
                }
                else if(e.kind == EventKind.EKeyDown && e.keyCode == Key.Z){
                    Root.instance.AddMsg(Undo);
                } 
                else if(e.kind == EventKind.EMove && (isRightButton || isLeftButton)){
                    TriggerEvent(lastPos, new Vector2(e.relX, e.relY));
                }      
                lastPos = new Vector2(e.relX, e.relY);
            case RefreshCanvas:
                RefreshGrids();
            default:
        }
    }


    function TriggerEvent(start:Vector2, end:Vector2) {
        var bm = m_view.bitmap_canvas;
        var mat = bm.getAbsPos();
        var pos = new Vector2(mat.x, mat.y);
        var gw = bm.width * mat.a / data_canvas.width;
        var gh = bm.height * mat.d / data_canvas.height;
        var minx = Math.min(start.x, end.x) - pos.x;
        var maxx = Math.max(start.x, end.x) - pos.x;
        var miny = Math.min(start.y, end.y) - pos.y;
        var maxy = Math.max(start.y, end.y) - pos.y;
        var sx = Math.clampInt(Math.floor(minx / gw), 0, data_canvas.width);
        var ex = Math.clampInt(Math.ceil(maxx / gw) + 1, 0, data_canvas.width);
        var sy = Math.clampInt(Math.floor(miny / gh), 0, data_canvas.height);
        var ey = Math.clampInt(Math.ceil(maxy / gh) + 1, 0, data_canvas.height);
        start.x = (start.x - pos.x) / gw;
        start.y = (start.y - pos.y) / gw;
        end.x = (end.x - pos.x) / gh;
        end.y = (end.y - pos.y) / gh;

        var list = new Array<IntVector2>();
        for (x in sx ... ex) for (y in sy ... ey){
            list.push(new IntVector2(x, y));
        }
        var color = isLeftButton ? 0 : 0xffffff;
        var layer = data_canvas.curLayer;
        var len = list.length;
        var lastCmd = null;
        for (i in 0 ... len){

            var pos = list[i];
            if( !IsInRect(pos.x, pos.y, 1, 1, start) &&  
                !IsInRect(pos.x, pos.y, 1, 1, end) &&  
                !IsIntersect(pos.x, pos.y, 1, 1, start, end)){
                continue;
            }
            var cmd = new Cmd_DrawPixel(pos.x, pos.y, layer, color );
            root_cmd.AddCmd(cmd);
            lastCmd = cmd;
        }
        if(lastCmd != null){
            lastCmd.AddCallback_Do(()->{
                RefreshGrids();
                root.AddMsg(RefreshTimeline);
            });
            lastCmd.AddCallback_Undo(()->{
                RefreshGrids();
                root.AddMsg(RefreshTimeline);
            });
        }
        
    }

    //检测相交
    function IsIntersect(x, y, width, height, start:Vector2, end:Vector2) : Bool {
        if( IsLineIntersect(x, y, x + width, y, start.x, start.y, end.x, end.y) || 
            IsLineIntersect(x + width, y, x + width, y + height, start.x, start.y, end.x, end.y) ||
            IsLineIntersect(x + width, y + height, x , y + height, start.x, start.y, end.x, end.y) ||
            IsLineIntersect(x, y + height, x, y, start.x, start.y, end.x, end.y)){
            return true;
        }
        return false;
    }

    function IsInRect(x, y, width, height, point:Vector2) {
        return point.x > x && point.x < x + width && point.y > y && point.y < y + height;
    }

    //检测线段是否相交
    function IsLineIntersect(x0:Float, y0:Float, x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, y3:Float) {
        var ax = x2 - x0;
        var bx = x3 - x2;
        var cx = x1 - x0;
        var ay = y2 - y0;
        var by = y3 - y2;
        var cy = y1 - y0;
        if(cy * bx - cx * by == 0){
            return false;
        }
        var m = (cx * ay - cy * ax) / (cy * bx - cx * by);
        var n = 0.0;
        if(cx != 0){
            n = ax / cx + bx / cx * m; 
        }
        else if(cy != 0) {
            n = ay / cy + by / cy * m; 
        }
        else{
            return false;
        }
        return m < 1 && m > 0 && n < 1 && n > 0; 
    }

    function RefreshGrids() {  
        m_view.bitmap_canvas.tile = Tile.fromPixels(data_canvas.GetFinalPixels());    
             
    }


}